/*
 * @FileName: easy_serial.c
 * @Author: GreyQiu qiushaogui@aikosolar.com
 * @Date: 2023-08-21 16:44:35
 * @LastEditors: GreyQiu qiushaogui@aikosolar.com
 * @LastEditTime: 2023-09-23 14:31:13
 * @Description: 
 * 
 * Copyright (c) 2023, All Rights Reserved. 
 */

#include "easy_serial.h"
#include "crc.h"
#include "bsp.h"

uint16_t tx_buffer[PKG_LEN];

/**
 * @description: 回复
 * @param {uint8_t} cmd
 * @param {uint8_t} err_code
 * @return {*}
 */
void easy_serial_ack(uint16_t cmd, uint16_t ack_code, uint16_t * data, uint16_t len)
{
    uint16_t idx = 0;

    for (uint16_t i = 0; i < PKG_LEN; i++)
    {
        tx_buffer[0] = 0;
    }

    tx_buffer[idx++] = 0x7e; // 帧头
    tx_buffer[idx++] = 0x80; // 帧序号高8位
    tx_buffer[idx++] = 0x00; // 帧序号低8位
    tx_buffer[idx++] = cmd;  // 命令码
    tx_buffer[idx++] = ack_code; // 操作结果
    tx_buffer[idx++] = len >> 8; // 数据长度高8位
    tx_buffer[idx++] = len & 0xFF; // 数据长度低8位

    for (uint16_t i = 0; i < len; i++)
    {
        tx_buffer[idx++] = data[i];
    }

    uint16_t crc = crc16(&tx_buffer[1], PKG_LEN - 4);
    tx_buffer[IDX_CRC16_H] = crc >> 8; // 校验和高8位
    tx_buffer[IDX_CRC16_L] = crc & 0x00FF; // 校验和低8位

    tx_buffer[IDX_TAIL] = 0x7e;
    // log_debug("err_code = %d --- crc = 0x%04x\n", err_code, checksum);
    bsp_wifi_uart_send(tx_buffer, PKG_LEN);
}

/**
 * @description: 传输层数据帧的解析处理, 自动从入参中的命令表中查找命令回调
 * @param buffer 要解析的帧地址
 * @param len 要解析的帧长度
 * @param cmd_tbl 命令表
 * @param tbl_len 命令表长度
 * @return NONE
 */
void easy_serial_process(uint16_t * buffer, uint32_t len, cmd_obj_t * cmd_tbl, uint16_t tbl_len)
{
//     log_debug("data get: len = %d\n", len);
//     for (size_t i = 0; i < 11; i++)
//     {
//         log_debug("0x%02x ", buffer[i]);
//     }
//     log_debug("......\n");

    // 帧长度异常，不响应
    if (len != PKG_LEN) {
        return;
    }
    // 帧头帧尾判断不符合协议规定，不响应
    if (buffer[IDX_HEADER] != PKG_HEADER || buffer[IDX_TAIL] != PKG_TAIL) {
        log_debug("invalid package....\n");
        return;
    }
    uint16_t cmd = buffer[IDX_CMD]; // 获取命令码
    uint16_t operate = buffer[IDX_RW]; // 获取操作码
    cmd_obj_t * obj = NULL;
    // log_debug("cmd = %d\n", cmd);
    // log_debug("operate = %d\n", operate);
    // 从表中顺序查找命令，如果命令表长度很大，建议使用二分查找
    uint16_t i;
    for (i = 0; i < tbl_len; i++) {
        if (cmd_tbl[i].cmd == cmd) {
            obj = &cmd_tbl[i];
            break;
        }
    }

    // 
    // if (i >= tbl_len) {
    //     aiko_bus_ack_err(cmd, ERROR_PERMISSION); // 回复无操作权限
    //     return;
    // }
    // 判断命令是否支持
    if (obj == NULL || (obj->permission & operate) == 0) {
        log_debug("cmd error...\n");
        easy_serial_ack(cmd, ACK_ERROR, NULL, 0); // 回复错误
        return;
    }

    // 校验数据
    uint16_t chksum1 = (buffer[IDX_CRC16_H] << 8) + buffer[IDX_CRC16_L]; // 获取校验和
    uint16_t chksum2 = crc16(&buffer[1], PKG_LEN - 4); // 计算校验和
    // log_debug("chksum1 = 0x%04x     chksum2 = 0x%04x\n", chksum1, chksum2);
    if (chksum1 != chksum2) {
        log_debug("crc error...\n");
        easy_serial_ack(cmd, ACK_ERROR, NULL, 0); // 回复错误
        return;
    };

    uint16_t vaild_len = (buffer[IDX_DATA_LEN_H] << 8) + buffer[IDX_DATA_LEN_L]; // 获取有效数据长度
    // 执行回调
    if (obj->handler != NULL) {
        obj->handler(cmd, buffer + IDX_VAILD_DATA, vaild_len, operate);
    }
}
